﻿using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Storage;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Threading.Tasks;

namespace Handday.Erp.Core
{
    /// <summary>
    /// 事务单元
    /// </summary>
    public interface IUnitOfWork : IDisposable
    {

        /// <summary>
        /// 完成
        /// </summary>
        Task CompleteAsync();
    }

    /// <summary>
    /// 事务单元管理器
    /// </summary>
    public interface IUnitOfWorkManager : IDisposable
    {
        /// <summary>
        /// 开启事务单元
        /// </summary>
        /// <returns></returns>
        IUnitOfWork Begin(Transactional transactional = Transactional.Required);
    }

    /// <summary>
    /// 事务单元
    /// </summary>
    public class UnitOfWork : IUnitOfWork
    {
        private readonly DbContext _dbContext;
        private readonly IDbContextTransaction _dbContextTransaction;
        private readonly Transactional _transactionalType;

        /// <summary>
        /// ctor
        /// </summary>
        public UnitOfWork(
            DbContext dbContext,
            IDbContextTransaction dbContextTransaction,
            Transactional transactionalType)
        {
            _dbContext = dbContext;
            _dbContextTransaction = dbContextTransaction;
            _transactionalType = transactionalType;
        }

        /// <summary>
        /// complete
        /// </summary>
        public async Task CompleteAsync()
        {
            await _dbContextTransaction?.CommitAsync();
        }

        /// <summary>
        /// dispose
        /// </summary>
        public void Dispose()
        {
            _dbContextTransaction?.Dispose();
            if (_transactionalType == Transactional.RequiresNew)
            {
                _dbContext?.Dispose();
            }
        }
    }

    /// <summary>
    /// 事务单元管理器
    /// </summary>
    public class UnitOfWorkManager<TDbContext> : IUnitOfWorkManager where TDbContext : DbContext
    {
        private readonly IServiceProvider _serviceProvider;

        /// <summary>
        /// ctor
        /// </summary>
        public UnitOfWorkManager(IServiceProvider serviceProvider)
        {
            _serviceProvider = serviceProvider;
        }

        public IUnitOfWork Begin(Transactional transactional = Transactional.Required)
        {
            IDbContextTransaction dbContextTransaction = null;
            TDbContext dbContext = null;
            if (transactional == Transactional.Required)
            {
                dbContext = _serviceProvider.GetRequiredService<TDbContext>();
            }
            else
            {
                var provider = _serviceProvider.CreateScope().ServiceProvider;
                dbContext = provider.GetRequiredService<TDbContext>();
            }

            if (dbContext.Database.CurrentTransaction == null)
            {
                dbContextTransaction = dbContext.Database.BeginTransaction();
            }

            return new UnitOfWork(dbContext, dbContextTransaction, transactional);
        }

        public void Dispose()
        {

        }
    }

    public enum Transactional
    {
        /// <summary>
        /// 当前域有事务则加入；无，则创建
        /// </summary>
        Required = 0,

        /// <summary>
        /// 始终创建新连接事务
        /// </summary>
        RequiresNew = 1
    }
}
